<?php

class ReadableRecordFactory {
	protected $db_host;
	protected $db_port;
	protected $db_user;
	protected $db_pass;
	protected $db_name;
	protected $db_handle;
	
	public function __construct($host, $user, $pass, $db, $port=3306) {
		$this->db_host = $host;
		$this->db_user = $user;
		$this->db_pass = $pass;
		$this->db_name = $db;
		$this->db_port = $port;
	}

	protected function getTableName($class_name) {
		return call_user_func(array($class_name, 'getTableName'));
	}
	
	protected function getObjectArray($class_name, $statement) {
		$set = array();
		while ($obj = $statement->fetchObject($class_name, array(false))) {
			$set[] = $obj;
		}

		return $set;
	}
	
	public function getDbHandle() {
		return MySQLConnectionPool::getConnection(
			$this->db_host,
			$this->db_port,
			$this->db_name,
			$this->db_user,
			$this->db_pass,
			MySQLConnectionPool::ERRMODE_EXCEPTION
		);
	}


	public function findBySql($class_name, $sql) {
		$statement = $this->getDbHandle()->prepare($sql);
		$exec_ret = $statement->execute();
		if (!$exec_ret) {
			error_log("ERROR CLASS:" . __CLASS__ . ", FUNCTION: " . __FUNCTION__ . ", LINE: " . __LINE__);
			error_log("ERROR - SQL FAILS: $sql");
			error_log(print_r($statement->errorInfo(), TRUE));
			return FALSE;
		}

		return $this->getObjectArray($class_name, $statement);
	}
	
	public function find($class_name, $where_sql = "", array $where_values = array(), $order_sql = "", $limit_sql = "") {
		if ($where_sql) {
			$where_sql = "WHERE $where_sql";
		}
		
		if ($order_sql) {
			$order_sql = "ORDER BY $order_sql";
		}

		if ($limit_sql) {
			$limit_sql = "LIMIT $limit_sql";
		}

		$table_name = $this->getTableName($class_name);
		$sql = "SELECT * FROM `$table_name` $where_sql $order_sql $limit_sql";
		$statement = $this->getDbHandle()->prepare($sql);

		foreach (array_values($where_values) as $k => $v) {
			$statement->bindValue($k+1, $v);
		}

		$exec_ret = $statement->execute();
		if (!$exec_ret) {
			error_log("ERROR CLASS:" . __CLASS__ . ", FUNCTION: " . __FUNCTION__ . ", LINE: " . __LINE__);
			error_log("ERROR - SQL FAILS: $sql");
			error_log("Parameters: " . print_r(@where_values, TRUE));
			error_log(print_r($statement->errorInfo(), TRUE));
			return FALSE;
		}

		return $this->getObjectArray($class_name, $statement);
	}

	public function findFields($class_name, $fields, $where_sql = "", array $where_values = array(), $order_sql = "", $limit_sql = "") {
		$field_sql = join(',', $fields);

		if ($where_sql) {
			$where_sql = "WHERE $where_sql";
		}
		
		if ($order_sql) {
			$order_sql = "ORDER BY $order_sql";
		}

		if ($limit_sql) {
			$limit_sql = "LIMIT $limit_sql";
		}

		$table_name = $this->getTableName($class_name);
		$sql = "SELECT $field_sql FROM `$table_name` $where_sql $order_sql $limit_sql";
		$statement = $this->getDbHandle()->prepare($sql);

		foreach (array_values($where_values) as $k => $v) {
			$statement->bindValue($k+1, $v);
		}

		$exec_ret = $statement->execute();
		if (!$exec_ret) {
			error_log("ERROR CLASS:" . __CLASS__ . ", FUNCTION: " . __FUNCTION__ . ", LINE: " . __LINE__);
			error_log("ERROR - SQL FAILS: $sql");
			error_log("Parameters: " . print_r(where_values, TRUE));
			error_log(print_r($statement->errorInfo(), TRUE));
			return FALSE;
		}
		
		if (sizeof($fields) > 1) return $statement->fetchAll(PDO::FETCH_ASSOC);
        else return $statement->fetchAll(PDO::FETCH_COLUMN);
	}

	public function findAll($class_name) {
		return $this->find($class_name);
	}
	
	public function findInstance($class_name, $keys) {
		$object = new $class_name();
		$required_keys = $object->getPrimaryKey();

		$wheres = array();
		foreach ($required_keys as $v) {
			$wheres[] = "$v = ?";
		}
		$where_sql = join(' AND ', $wheres);
		$key_argument = is_array($keys) ? $keys : array($keys);

		return array_shift($this->find($class_name, $where_sql, $key_argument));
	}
}
?>